package com.learning.spring.aop.advisor.advisor.dynamic;

import com.learning.spring.aop.advisor.service.AopService;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.DynamicMethodMatcherPointcut;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * ClassName: AopDynamicPointcut
 * Description: 动态切面- DynamicMethodMatcherPointcut、DefaultPointcutAdvisor
 * <p>
 * 1. 定义一个动态切点
 * 1.1 重写 getClassFilter 方法，限定被代理的类
 * 1.2 重写 matches(Method method, Class<?> targetClass) 方法，进行静态切点检查。建议所有的动态切点都重写静态切点检查，提高效率（先匹配静态，后匹配动态）。
 * 1.3 重写 matches(Method method, Class<?> targetClass, Object... args) 方法，进行动态切点检查。
 * <p>
 * 2. 动态切面由于其本身功能的实现限制，对于性能的影响比较大，不建议使用，后者配合静态切点检查一起使用。
 * <p>
 * Date: 2019/4/21 15:40 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class AopDynamicPointcut extends DynamicMethodMatcherPointcut {
    private static final String METHOD_NAME = "add";
    private static List<String> specialClientList = new ArrayList<>();

    static {
        // 模拟参数，是由 add 方法传入参数是 Sam 时才匹配
        specialClientList.add("Sam");
    }

    @Override
    public ClassFilter getClassFilter() {
        return AopService.class::isAssignableFrom;
    }

    /**
     * 静态切点检查，对方法名进行限制。
     * 这边不通过，则不必要进行动态检查，提高效率
     *
     * @param method
     * @param targetClass
     * @return
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        System.out.println("++ 对方法 " + method.getName() + " 做静态检查");
        return Objects.equals(METHOD_NAME, method.getName());
    }

    /**
     * 动态切点检查。
     * 性能影响较大，不建议使用。
     *
     * @param method
     * @param targetClass
     * @param args
     * @return
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass, Object... args) {
        System.out.println("~~ 对方法 " + method.getName() + " 做动态检查");
        if (Objects.isNull(args) || args.length == 0) {
            return false;
        }
        String clientName = (String) args[0];
        return specialClientList.contains(clientName);
    }
}